#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string>
#include <unistd.h>
#include <netinet/in.h>
#include <time.h>
#include <sstream>

using namespace std;

#define NTP_PORT 123
#define NTP_PACKET_SIZE 48

#define BUFFSIZE 1024
#define SEP "\r" 
#define LINE_SEP "\n"
#define SEP_LEN strlen(SEP)
#define LINE_SEP_LEN strlen(LINE_SEP)


typedef struct NtpPacket{
    //这个数据结构中，mode表示数据包的模式，共有3位，其中最后一位表示包尾，为0表示包尾，为1表示包首。
    //vn表示虚拟节点号，共有3位，用于标识不同的NTP服务器。
    //li表示链路标识符，共有5位，用于标识不同的网络链路。
    unsigned char mode : 3;
    unsigned char vn : 3;
    unsigned char li : 2;

    unsigned char stratum;
    unsigned char poll;
    unsigned char precision;

    unsigned int root_delay;
    unsigned int root_dispersion;
    unsigned int reference_identifier;

    unsigned int reference_timestamp;//表示参考时间戳，表示NTP服务器收到请求包的时间戳。
    unsigned int originate_timestamp;//表示发起时间戳，表示客户端应用发出请求包的时间戳。
    unsigned int receive_timestamp;//表示接收时间戳，表示客户端应用收到响应包的时间戳。
    unsigned int transmit_timestamp;//表示发送时间戳，表示客户端应用发出响应包的时间戳。
} Packet;


// mode=3 \r vn=4 \r li=0 \n ref_time=0 \r org_time=0 \r rec_time=0 \r tran_time=0 
std::string enLength(const std::string &text)
{

    string str = to_string(text.size());
    str += LINE_SEP;
    str += "mode=3";
    str += SEP;
    str += "vn=4";
    str += SEP;
    str += "li=0";
    str += LINE_SEP;
    // 长度 \n mode=3 \r vn=4 \r li=0 \n
    string send_str = str;
    send_str += "text:";
    send_str += text;
    send_str += LINE_SEP;
    // 长度 \n mode=3 \r vn=4 \r li=0 \n  text: text  \n

    return send_str;
}

bool deLength(const std::string &package, std::string *text)
{   
    // 长度 \n mode=3 \r vn=4 \r li=0 \n  text  \n
    auto pos = package.find(LINE_SEP);
    if (pos == std::string::npos)
        return false;
    std::string text_len_string = package.substr(0, pos);
    int text_len = std::stoi(text_len_string);
    auto new_pos = package.find("text:");
    int len = strlen("text:");
    *text = package.substr(new_pos + len, text_len);
    return true;
}

bool recvPackage(int sock, std::string &inbuffer, std::string *text)
{
    char buffer[1024];
        // 长度 \n mode=3 \r vn=4 \r li=0 \n  text  \n
        ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
        while(1)
        {
            if (n > 0)
            {
                buffer[n] = 0;
                inbuffer += buffer;
                break;
            }
            else
                return false;
        }
    return true;
}

class Request
{
public:
    Request()
    {
        memset(&pkt, 0, NTP_PACKET_SIZE);
        pkt.li = 0;
        pkt.vn = 4;
        pkt.mode = 3;
    }
     bool serialize(std::string *out)
    {
        // unsigned int reference_timestamp;//表示参考时间戳，表示NTP服务器收到请求包的时间戳。
        //# unsigned int originate_timestamp;//表示发起时间戳，表示客户端应用发出请求包的时间戳。
        // unsigned int receive_timestamp;//表示接收时间戳，表示客户端应用收到响应包的时间戳。
        // unsigned int transmit_timestamp;//表示发送时间戳，表示客户端应用发出响应包的时间戳。
        // mode=3 \r vn=4 \r li=0 \n org_time=0 \r ref_time=0 \r rec_time=0 \r tran_time=0 
        *out = "";
        time_t tim;
        long timestamp = time(&tim);//orgin_time
        ostringstream oss;
        oss<< timestamp;
        string timestamp_str = oss.str();

        // *out += "org_time=";
        *out += timestamp_str;
        *out += SEP;
        //time_str SEP
        sleep(3);
        return true;
    }
    bool deserialize(const std::string &in)
    {
        
    }
private:
    Packet pkt;
};
class Response
{
public:
    Response():time("nullptr")
    {}
    Response(string time):time(time)
    {}
    bool serialize(std::string *out)
    {
        
    }
    bool deserialize(const std::string &in)
    {
        time_t time_stamp = stoi(in); // 时间戳，单位为秒
        struct tm *timeinfo;
        char buffer[80];
        timeinfo = localtime(&time_stamp); // 将时间戳转换为本地时间
        strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
        
        time = buffer;
        return true;
    }
public:
    //0表示成功
    // int exit_code;
    //真实时间表示成功例如，Tue Nov 14 00:17:45 2023
    string time;
};